package onvif

import (
	"encoding/xml"
	"fmt"
	"strings"
	"time"

	"github.com/videonext/onvif/discovery"
	"github.com/videonext/onvif/profiles/devicemgmt"
	"github.com/videonext/onvif/profiles/media"
	"github.com/videonext/onvif/soap"
)

//获取到的原始数据
type OnvifUrlMesage struct {
	XAddr       string
	ShapshotUrl string
	StreamUrl   string
}

//扫描所有设备
func GetAllOnVifDevice() ([]discovery.Device, error) {
	return discovery.StartDiscovery(1 * time.Second)
}

//获取设备的服务信息
func GetDeviceInformation(xaddr string, user string, password string) (*devicemgmt.GetDeviceInformationResponse, error) {
	client := soap.NewClient(
		soap.WithTimeout(time.Second * 1),
	)
	client.AddHeader(soap.NewWSSSecurityHeader(user, password, time.Now()))
	dev := devicemgmt.NewDevice(client, xaddr)
	reply, err := dev.GetDeviceInformation(&devicemgmt.GetDeviceInformation{})
	return reply, err
}

//获取设备所有的服务
func GetDeviceServices(xaddr string, user string, password string) (*devicemgmt.GetServicesResponse, error) {
	client := soap.NewClient(
		soap.WithTimeout(time.Second * 1),
	)
	client.AddHeader(soap.NewWSSSecurityHeader(user, password, time.Now()))
	dev := devicemgmt.NewDevice(client, xaddr)
	reply, err := dev.GetServices(&devicemgmt.GetServices{})
	return reply, err
}

//指定获取某个服务，例如"media"
func GetAssignDeviceServices(assign string, xaddr string, user string, password string) (devicemgmt.Service, error) {
	client := soap.NewClient(
		soap.WithTimeout(time.Second * 1),
	)
	client.AddHeader(soap.NewWSSSecurityHeader(user, password, time.Now()))
	dev := devicemgmt.NewDevice(client, xaddr)
	reply, err := dev.GetServices(&devicemgmt.GetServices{})
	var response devicemgmt.Service
	if err == nil {
		for _, vaule := range reply.Service {
			if strings.Contains(string(vaule.Namespace), assign) {
				response = vaule
				break
			}
		}
	}
	return response, err
}

//已知xaddr,namespace获取抓图的url地址
func GetShapshotUrl(xaddr string, namespace string, user string, password string) (string, error) {
	var addr string
	client := soap.NewClient(
		soap.WithTimeout(time.Second * 1),
	)
	client.AddHeader(soap.NewWSSSecurityHeader(user, password, time.Now()))

	dev := media.NewMedia(client, xaddr)
	reply, err := dev.GetProfiles(&media.GetProfiles{XMLName: xml.Name{Space: namespace, Local: "GetProfiles"}})
	if err != nil || len(reply.Profiles) == 0 {
		return addr, err
	}

	reply1, err := dev.GetSnapshotUri(&media.GetSnapshotUri{XMLName: xml.Name{Space: namespace, Local: "GetSnapshotUri"}, ProfileToken: reply.Profiles[0].Token})
	if err != nil {
		return addr, err
	}

	addr = string(reply1.MediaUri.Uri)

	return addr, err
}
func GetStreamUrl(xaddr string, namespace string, user string, password string) (string, error) {
	var addr string
	client := soap.NewClient(
		soap.WithTimeout(time.Second * 1),
	)
	client.AddHeader(soap.NewWSSSecurityHeader(user, password, time.Now()))

	dev := media.NewMedia(client, xaddr)
	reply, err := dev.GetProfiles(&media.GetProfiles{XMLName: xml.Name{Space: namespace, Local: "GetProfiles"}})
	if err != nil || len(reply.Profiles) == 0 {
		return addr, err
	}

	reply1, err := dev.GetStreamUri(&media.GetStreamUri{XMLName: xml.Name{Space: namespace, Local: "GetStreamUri"}, ProfileToken: reply.Profiles[0].Token})
	if err != nil {
		return addr, err
	}

	addr = string(reply1.MediaUri.Uri)

	return addr, err
}

//according to IP获取摄像头截图的url
func GetShapshotUrlByIP(ip string, user string, password string) (string, bool) {
	var addr string
	devices, err := GetAllOnVifDevice()
	if err != nil {
		return addr, false
	}
	for _, vaule := range devices {
		if strings.Contains(string(vaule.XAddr), ip) {
			mediaServe, err := GetAssignDeviceServices("media", vaule.XAddr, user, password)
			if err != nil {
				return addr, false
			}
			addr, err = GetShapshotUrl(string(mediaServe.XAddr), string(mediaServe.Namespace), user, password)
			if err != nil {
				return addr, false
			}
			return addr, true
		}
	}
	return addr, false
}

func GetAllOnvifUrlMesage(user string, password string) []OnvifUrlMesage {
	onvifUrlMesages := []OnvifUrlMesage{}

	//start_time := time.Now().UnixNano() / int64(time.Millisecond)

	devices, err := GetAllOnVifDevice()
	if err != nil {
		return onvifUrlMesages
	}
	//pretty.Println(devices)
	//fmt.Println("expend：", time.Now().UnixNano()/int64(time.Millisecond)-start_time)

	for _, vaule := range devices {
		mediaServe, err := GetAssignDeviceServices("media", vaule.XAddr, user, password)
		if err != nil {
			continue
		}
		shapshotUrl, err := GetShapshotUrl(string(mediaServe.XAddr), string(mediaServe.Namespace), user, password)
		if err != nil {
			continue
		}
		streamUrl, err := GetStreamUrl(string(mediaServe.XAddr), string(mediaServe.Namespace), user, password)
		if err != nil {
			continue
		}
		onvifUrlMesage := OnvifUrlMesage{vaule.XAddr, shapshotUrl, streamUrl}

		onvifUrlMesages = append(onvifUrlMesages, onvifUrlMesage)
	}
	return onvifUrlMesages
}

func getHttpJpge(url string, fname string) bool {

	return true
}

func GetShapJPGEbyURL(shapshotUrl string, add string) string {
	var read_url string
	kv := strings.Split(shapshotUrl, "//")
	if len(kv) == 2 {
		read_url = kv[0] + add + kv[1]
	}
	read_url = strings.Replace(read_url, " ", "", -1)
	return read_url
}

func WgetJPGE(shapshotUrl string, add string, save string) {
	//start_time := time.Now().UnixNano() / int64(time.Millisecond)
	read_url := GetShapJPGEbyURL(shapshotUrl, add)
	if read_url != "" {
		//fmt.Println("url:", read_url, ",", save)
		ret := getHttpJpge(read_url, save)
		if ret == false {
			fmt.Printf("get[%s]：[%s] is err\r\n", save, shapshotUrl)
			return
		}
	}
	//fmt.Printf("get[%s]：[%s] expend：%d\r\n", save, read_url, time.Now().UnixNano()/int64(time.Millisecond)-start_time)
}

//according to IP获取摄像头xaddr
func GetXaddrByIP(ip string) (string, bool) {
	devices, err := GetAllOnVifDevice()
	if err != nil {
		return "", false
	}
	for _, vaule := range devices {
		if strings.Contains(string(vaule.XAddr), ip) {
			return vaule.XAddr, true
		}
	}
	return "", false
}

func SetCameraIP(xaddr string, user string, password string, ip string) bool {
	//GetNetworkInterfaces
	client := soap.NewClient(
		soap.WithTimeout(time.Second * 1),
	)
	client.AddHeader(soap.NewWSSSecurityHeader(user, password, time.Now()))
	dev := devicemgmt.NewDevice(client, xaddr)
	reply, err := dev.GetNetworkInterfaces(&devicemgmt.GetNetworkInterfaces{})
	if err != nil || len(reply.NetworkInterfaces) == 0 {
		return false
	}

	reply.NetworkInterfaces[0].IPv4.Config.Manual[0].Address = devicemgmt.IPv4Address(ip)

	networkInterface := devicemgmt.NetworkInterfaceSetConfiguration{
		Enabled: reply.NetworkInterfaces[0].Enabled,
		//Link: devicemgmt.NetworkInterfaceConnectionSetting{
		//	AutoNegotiation: reply.NetworkInterfaces[0].Link.AdminSettings.AutoNegotiation,
		//	Speed:           reply.NetworkInterfaces[0].Link.AdminSettings.Speed,
		//	Duplex:          reply.NetworkInterfaces[0].Link.AdminSettings.Duplex,
		//},
		//MTU: reply.NetworkInterfaces[0].Info.MTU,
		IPv4: devicemgmt.IPv4NetworkInterfaceSetConfiguration{
			Enabled: reply.NetworkInterfaces[0].IPv4.Enabled,
			Manual:  reply.NetworkInterfaces[0].IPv4.Config.Manual,
			DHCP:    reply.NetworkInterfaces[0].IPv4.Config.DHCP,
		},
		//IPv6: devicemgmt.IPv6NetworkInterfaceSetConfiguration{
		//	Enabled: reply.NetworkInterfaces[0].IPv6.Enabled,
		//},
		//Extension: devicemgmt.NetworkInterfaceSetConfigurationExtension{
		//	Dot3:  reply.NetworkInterfaces[0].Extension.Dot3,
		//	Dot11: reply.NetworkInterfaces[0].Extension.Dot11,
		//},
		//Enabled: reply.NetworkInterfaces[0].Enabled,
	}

	_, err = dev.SetNetworkInterfaces(
		&devicemgmt.SetNetworkInterfaces{
			InterfaceToken:   reply.NetworkInterfaces[0].Token,
			NetworkInterface: networkInterface,
		},
	)

	if err == nil {
		return true
	}

	return false

}
